#ifndef _COMM_HPP_
#define _COMM_HPP_

#include<iostream>
#include<cerrno>
#include<cstring>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
using namespace std;


//创建key需要的参数
#define PATHNAME "." //路径选择在当前工作目录
#define PROJ_ID 0X66 //ID随便选择一个数

#define MAX_SIZE 4096 //要开的共享内存的大小
    
//1:封装接口(获取key值（ftok）)
key_t getKey(){
    key_t k = ftok(PATHNAME,PROJ_ID);//获取key值返回到k中
    if(k < 0){
        cerr<<errno<<":"<<strerror(errno)<<endl;
        exit(1);
    }

    return k;
}

//2：封装shmget：
//2.1：第一种情况：客户端是要获取共享内存的
//2.2：第二种情况：服务端是用来创建共享内存的
int getShmHelper(key_t k,int shmflg){
    int shmid = shmget(k,MAX_SIZE,shmflg);
    if(shmid < 0){
        cerr<<errno<<":"<<strerror(errno)<<endl;
        exit(2);
    }
    return shmid;
}

int getshm(key_t k){
    //通过2种不同的情况分别进行封装
    int ret = getShmHelper(k,IPC_CREAT);
    return ret;
}

int creatshm(key_t k){
    int ret = getShmHelper(k,IPC_CREAT | IPC_EXCL | 0600);
    return ret;
}


//3:封装删除共享内存的接口
void deleteShm(int shmid){
    //如果等于-1就说明删除失败
    if(shmctl(shmid,IPC_RMID,nullptr) == -1){
        cerr<<errno<<":"<<strerror(errno)<<endl;
        exit(3);
    }
}

//4:封装挂接的接口：shmat
//挂接失败返回-1
void* attachShm(int shmid){
    void* ret = shmat(shmid,nullptr,0);
    //因为返回值是void*类型，所以要强制转换才能能进行比较
    if((long long)ret == -1L){
        cerr<<errno<<":"<<strerror(errno)<<endl;
        exit(4);
    }
    return ret;
}

//5:封装去除关联性的接口：shmdt
//去除失败返回-1
//传入的要去除关联性的初始地址
void detachShm(void* start){
    if(shmdt(start) == -1){
        cerr<<errno<<":"<<strerror(errno)<<endl;
        exit(5);
    }
}
#endif